package com.pai4j.user.service.group;

import com.pai4j.common.enums.*;
import com.pai4j.common.enums.messagequeue.MessageBroadChannelEnum;
import com.pai4j.common.exception.BusinessException;
import com.pai4j.common.service.messagequeue.producer.MessageQueueProducer;
import com.pai4j.domain.vo.request.group.ApplyJoinGroupRequestVO;
import com.pai4j.domain.vo.request.group.HandleJoinApplicationRequestVO;
import com.pai4j.domain.vo.request.group.JoinGroupRequestVO;
import com.pai4j.domain.vo.request.mess.MessageNotifyVO;
import com.pai4j.domain.vo.response.UserBaseResponseInfoVO;
import com.pai4j.domain.vo.response.group.GroupJoinApplicationResponseVO;
import com.pai4j.domain.vo.response.group.JoinGroupResponseVO;
import com.pai4j.user.repository.dao.*;
import com.pai4j.user.repository.entity.*;
import com.pai4j.user.service.UserService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import com.pai4j.common.util.RedisUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;


/**
 * 加群申请审批服务
 * 参考GroupInvitationService设计，实现加群审批流程
 */
@Slf4j
@Service
public class GroupJoinApplicationService {

    @Resource
    private IGroupJoinApplicationDAO groupJoinApplicationDAO;
    
    @Resource
    private IGroupInfoDAO groupInfoDAO;
    
    @Resource
    private IGroupMemberDAO groupMemberDAO;
    
    @Resource
    private IGroupOperationLogDAO groupOperationLogDAO;
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private GroupMemberService groupMemberService;
    
    @Autowired
    private RedisUtil redisUtil;
    
    @Autowired
    private com.pai4j.user.service.approval.PendingApprovalService pendingApprovalService;
    
    @Autowired
    private MessageQueueProducer messageQueueProducer;
    
    // Redis缓存Key前缀
    private static final String CACHE_PREFIX_GROUP_PENDING_APPLICATIONS = "pai4j:group:pending:applications:";
    private static final String CACHE_PREFIX_USER_APPLICATION_STATUS = "pai4j:user:application:status:";
    
    // 缓存过期时间：1小时 = 3600秒
    private static final long CACHE_EXPIRE_SECONDS = 3600L;

    /**
     * 申请加入群聊
     * 当群设置为"需要审批"时，用户调用此方法提交申请
     */
    @Transactional
    public Long applyJoinGroup(ApplyJoinGroupRequestVO request) {
        // 1. 验证群聊是否存在
        GroupInfoEntity groupInfo = groupInfoDAO.findByPaiId(request.getGroupPaiId());
        if (groupInfo == null) {
            throw new BusinessException("群聊不存在");
        }
        
        // 2. 验证群状态
        if (!GroupStatusEnum.isNormal(groupInfo.getStatus())) {
            throw new BusinessException("群聊状态异常，无法加入");
        }
        
        // 3. 检查用户是否已在群内
        if (groupMemberDAO.existsByGroupPaiIdAndUserAccount(request.getGroupPaiId(), request.getApplicantAccount())) {
            throw new BusinessException("您已在该群内");
        }
        
        // 4. 检查群加入模式
        if (groupInfo.getJoinMode().equals(0)) {
            throw new BusinessException("该群无需审批，可以直接加入");
        } else if (groupInfo.getJoinMode().equals(2)) {
            throw new BusinessException("该群禁止加入");
        }
        
        // 5. 检查是否已有待处理的申请
        Long pendingCount = groupJoinApplicationDAO.countByGroupPaiIdAndApplicantAccountAndApplicationStatus(
                request.getGroupPaiId(), request.getApplicantAccount(), GroupInvitationStatusEnum.PENDING.getStatus());
        if (pendingCount > 0) {
            throw new BusinessException("您已提交过申请，请等待审批");
        }
        
        // 6. 检查群成员数量限制
        Long memberCount = groupMemberDAO.countActiveMembers(request.getGroupPaiId());
        if (memberCount >= groupInfo.getMaxMembers()) {
            throw new BusinessException("群成员已达上限");
        }
        
        // 7. 创建申请记录
        Date now = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, 7); // 默认7天过期
        Date expireTime = calendar.getTime();
        
        GroupJoinApplicationEntity application = new GroupJoinApplicationEntity();
        application.setGroupPaiId(request.getGroupPaiId());
        application.setApplicantAccount(request.getApplicantAccount());
        application.setApplicationMessage(request.getApplicationMessage());
        application.setApplicationStatus(GroupInvitationStatusEnum.PENDING.getStatus());
        application.setExpireTime(expireTime);
        application.setCreateDate(now);
        application.setUpdateDate(now);
        
        GroupJoinApplicationEntity savedApplication = groupJoinApplicationDAO.save(application);
        
        // 8. 【强一致性】同步为所有群主和管理员创建统一待审核记录
        // 【关键优化】确保每个管理员都能在“统一待审核列表”中看到该申请
        try {
            // 获取所有群主和管理员
            List<GroupMemberEntity> admins = groupMemberDAO.findGroupAdminsAndOwner(request.getGroupPaiId());
            
            if (admins.isEmpty()) {
                log.warn("群 {} 没有群主或管理员，跳过创建统一待审核记录", request.getGroupPaiId());
            } else {
                // 为每个管理员创建一条待审核记录
                for (GroupMemberEntity admin : admins) {
                    pendingApprovalService.createPendingApproval(
                            com.pai4j.common.enums.PendingApprovalTypeEnum.GROUP_JOIN_REQUEST.getType(),
                            savedApplication.getId(),
                            request.getApplicantAccount(),  // 申请人
                            admin.getUserAccount(),  // 审批人（当前管理员）
                            request.getGroupPaiId(),  // targetId（群组ID）
                            request.getApplicationMessage(),  // 申请留言
                            GroupInvitationStatusEnum.PENDING.getStatus(),
                            expireTime  // 过期时间
                    );
                }
                log.debug("加群申请同步为 {} 个管理员创建统一待审核记录成功：applicationId={}", 
                        admins.size(), savedApplication.getId());
            }
        } catch (Exception e) {
            log.error("加群申请同步创建统一待审核记录失败，事务将回滚：applicationId={}", savedApplication.getId(), e);
            throw new RuntimeException("创建统一待审核记录失败", e);
        }
        
        // 9. 记录操作日志
        recordOperationLog(request.getGroupPaiId(), request.getApplicantAccount(), null,
                String.valueOf(GroupOperationTypeEnum.JOIN_GROUP.getType()),
                          "用户申请加入群聊：" + (StringUtils.isNotBlank(request.getApplicationMessage()) 
                              ? request.getApplicationMessage() : "无留言"));
        
        // 10. 清除群待审批列表缓存
        clearGroupPendingApplicationsCache(request.getGroupPaiId());
        
        log.info("用户 {} 申请加入群 {}，申请ID：{}", request.getApplicantAccount(), request.getGroupPaiId(), savedApplication.getId());
        return savedApplication.getId();
    }

    /**
     * 通过加群申请（强一致性）
     * 参考User2UserAccountRelationService.confirmSubscribe设计
     * 备注为可选参数，如果提供备注则发送互动消息通知申请人
     * 
     * @param applicationId 申请ID
     * @param approverAccount 审批人账号
     * @param approvalRemark 审批备注（可选，传null表示无备注）
     * @return 是否成功
     */
    @Transactional
    public boolean approveJoinApplication(Long applicationId, String approverAccount, String approvalRemark) {
        // 1. 验证申请记录是否存在
        GroupJoinApplicationEntity application = groupJoinApplicationDAO.findById(applicationId)
                .orElseThrow(() -> new BusinessException("申请记录不存在"));
        
        // 2. 验证申请状态
        if (!GroupInvitationStatusEnum.isPending(application.getApplicationStatus())) {
            throw new BusinessException("该申请已被处理或已过期");
        }
        
        // 3. 验证过期时间
        if (application.getExpireTime() != null && application.getExpireTime().before(new Date())) {
            throw new BusinessException("该申请已过期");
        }
        
        // 4. 验证审批人权限（必须是群主或管理员）
        if (!groupMemberService.hasPermission(application.getGroupPaiId(), approverAccount, "admin")) {
            throw new BusinessException("您没有权限审批加群申请");
        }
        
        // 5. 更新申请状态
        Date now = new Date();
        application.setApplicationStatus(GroupInvitationStatusEnum.ACCEPTED.getStatus());
        application.setApproverAccount(approverAccount);
        application.setApprovalTime(now);
        application.setApprovalRemark(approvalRemark);
        application.setUpdateDate(now);
        
        groupJoinApplicationDAO.save(application);
        
        // 6. 【强一致性】同步更新统一待审核表状态
        try {
            pendingApprovalService.updateApprovalStatus(
                    com.pai4j.common.enums.PendingApprovalTypeEnum.GROUP_JOIN_REQUEST.getType(),
                    application.getId(),
                    GroupInvitationStatusEnum.ACCEPTED.getStatus(),
                    approverAccount,
                    StringUtils.isNotBlank(approvalRemark) ? approvalRemark : "加群申请已通过"
            );
            log.info("加群申请审批通过，统一待审核表已同步更新：applicationId={}", application.getId());
        } catch (Exception e) {
            log.error("同步更新统一待审核表失败，事务将回滚：applicationId={}", application.getId(), e);
            throw new RuntimeException("同步更新统一待审核表失败", e);
        }
        
        // 7. 调用joinGroup加入群聊
        // 注意：joinGroup会同时处理群成员表、账号关系表和缓存同步（强一致性）
        JoinGroupRequestVO joinRequest = new JoinGroupRequestVO();
        joinRequest.setGroupPaiId(application.getGroupPaiId());
        joinRequest.setUserAccount(application.getApplicantAccount());
        joinRequest.setJoinType(GroupJoinTypeEnum.APPROVED.getType()); // 审批通过加入
        joinRequest.setInviterAccount(approverAccount);
        
        try {
            // 调用统一的加群方法，确保数据一致性（群成员表+账号关系表+缓存）
            JoinGroupResponseVO joinResult = groupMemberService.joinGroup(joinRequest);
            if (joinResult.getStatus() == 1) {
                log.info("用户 {} 通过审批成功加入群聊 {}，审批人：{}，所有数据已同步（群成员表+账号关系表+缓存）", 
                        application.getApplicantAccount(), application.getGroupPaiId(), approverAccount);
            } else {
                log.warn("用户 {} 通过审批加入群聊 {} 未成功，状态：{}，消息：{}", 
                        application.getApplicantAccount(), application.getGroupPaiId(), joinResult.getStatus(), joinResult.getMessage());
                throw new BusinessException(joinResult.getMessage());
            }
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("用户 {} 通过审批加入群聊 {} 失败", application.getApplicantAccount(), application.getGroupPaiId(), e);
            throw new BusinessException("加入群聊失败：" + e.getMessage());
        }
        
        // 8. 记录操作日志
        String operationDesc = "审批通过加群申请";
        if (StringUtils.isNotBlank(approvalRemark)) {
            operationDesc += "，意见：" + approvalRemark;
        }
        
        recordOperationLog(application.getGroupPaiId(), approverAccount, application.getApplicantAccount(),
                String.valueOf(GroupOperationTypeEnum.JOIN_GROUP.getType()), operationDesc);
        
        // 9. 清除相关缓存
        clearGroupPendingApplicationsCache(application.getGroupPaiId());
        clearUserApplicationStatusCache(application.getGroupPaiId(), application.getApplicantAccount());
        
        log.info("审批人 {} 通过了用户 {} 的加群申请，群：{}", 
                approverAccount, application.getApplicantAccount(), application.getGroupPaiId());
        
        // 10. 如果有备注，发送互动消息通知申请人
        if (StringUtils.isNotBlank(approvalRemark)) {
            sendApprovalNotification(
                    approverAccount, 
                    application.getApplicantAccount(), 
                    application.getGroupPaiId(),
                    true, 
                    approvalRemark
            );
        }
        
        return true;
    }
    
    /**
     * 拒绝加群申请（强一致性）
     * 参考User2UserAccountRelationService.rejectSubscribe设计
     * 拒绝理由为可选参数，如果提供理由则发送互动消息通知申请人
     * 
     * @param applicationId 申请ID
     * @param approverAccount 审批人账号
     * @param approvalRemark 拒绝理由（可选，传null表示无理由）
     * @return 是否成功
     */
    @Transactional
    public boolean rejectJoinApplication(Long applicationId, String approverAccount, String approvalRemark) {
        // 1. 验证申请记录是否存在
        GroupJoinApplicationEntity application = groupJoinApplicationDAO.findById(applicationId)
                .orElseThrow(() -> new BusinessException("申请记录不存在"));
        
        // 2. 验证申请状态
        if (!GroupInvitationStatusEnum.isPending(application.getApplicationStatus())) {
            throw new BusinessException("该申请已被处理或已过期");
        }
        
        // 3. 验证审批人权限（必须是群主或管理员）
        if (!groupMemberService.hasPermission(application.getGroupPaiId(), approverAccount, "admin")) {
            throw new BusinessException("您没有权限审批加群申请");
        }
        
        // 4. 更新申请状态
        Date now = new Date();
        application.setApplicationStatus(GroupInvitationStatusEnum.REJECTED.getStatus());
        application.setApproverAccount(approverAccount);
        application.setApprovalTime(now);
        application.setApprovalRemark(approvalRemark);
        application.setUpdateDate(now);
        
        groupJoinApplicationDAO.save(application);
        
        // 5. 【强一致性】同步更新统一待审核表状态
        try {
            pendingApprovalService.updateApprovalStatus(
                    com.pai4j.common.enums.PendingApprovalTypeEnum.GROUP_JOIN_REQUEST.getType(),
                    application.getId(),
                    GroupInvitationStatusEnum.REJECTED.getStatus(),
                    approverAccount,
                    StringUtils.isNotBlank(approvalRemark) ? approvalRemark : "加群申请已拒绝"
            );
            log.info("加群申请拒绝，统一待审核表已同步更新：applicationId={}", application.getId());
        } catch (Exception e) {
            log.error("同步更新统一待审核表失败，事务将回滚：applicationId={}", application.getId(), e);
            throw new RuntimeException("同步更新统一待审核表失败", e);
        }
        
        // 6. 记录操作日志
        String operationDesc = "拒绝加群申请";
        if (StringUtils.isNotBlank(approvalRemark)) {
            operationDesc += "，理由：" + approvalRemark;
        }
        
        recordOperationLog(application.getGroupPaiId(), approverAccount, application.getApplicantAccount(),
                String.valueOf(GroupOperationTypeEnum.JOIN_GROUP.getType()), operationDesc);
        
        // 7. 清除相关缓存
        clearGroupPendingApplicationsCache(application.getGroupPaiId());
        clearUserApplicationStatusCache(application.getGroupPaiId(), application.getApplicantAccount());
        
        log.info("审批人 {} 拒绝了用户 {} 的加群申请，群：{}", 
                approverAccount, application.getApplicantAccount(), application.getGroupPaiId());
        
        // 8. 如果有理由，发送互动消息通知申请人
        if (StringUtils.isNotBlank(approvalRemark)) {
            sendApprovalNotification(
                    approverAccount, 
                    application.getApplicantAccount(), 
                    application.getGroupPaiId(),
                    false, 
                    approvalRemark
            );
        }
        
        return true;
    }

    /**
     * 处理加群申请（群主或管理员审批）
     * @deprecated 建议使用 approveJoinApplication 或 rejectJoinApplication 方法
     */
    @Transactional
    @Deprecated
    public boolean handleJoinApplication(HandleJoinApplicationRequestVO request) {
        // 1. 验证申请记录是否存在
        GroupJoinApplicationEntity application = groupJoinApplicationDAO.findById(request.getApplicationId())
                .orElseThrow(() -> new BusinessException("申请记录不存在"));
        
        // 2. 验证群组ID匹配
        if (!application.getGroupPaiId().equals(request.getGroupPaiId())) {
            throw new BusinessException("申请记录与群组不匹配");
        }
        
        // 3. 验证申请状态
        if (!GroupInvitationStatusEnum.isPending(application.getApplicationStatus())) {
            throw new BusinessException("该申请已被处理或已过期");
        }
        
        // 4. 验证过期时间
        if (application.getExpireTime() != null && application.getExpireTime().before(new Date())) {
            throw new BusinessException("该申请已过期");
        }
        
        // 5. 验证审批人权限（必须是群主或管理员）
        if (!groupMemberService.hasPermission(request.getGroupPaiId(), request.getApproverAccount(), "admin")) {
            throw new BusinessException("您没有权限审批加群申请");
        }
        
        // 6. 验证处理结果
        if (!GroupInvitationStatusEnum.isAccepted(request.getHandleResult()) 
            && !GroupInvitationStatusEnum.isRejected(request.getHandleResult())) {
            throw new BusinessException("无效的处理结果");
        }
        
        // 7. 更新申请状态
        Date now = new Date();
        application.setApplicationStatus(request.getHandleResult());
        application.setApproverAccount(request.getApproverAccount());
        application.setApprovalTime(now);
        application.setApprovalRemark(request.getApprovalRemark());
        application.setUpdateDate(now);
        
        groupJoinApplicationDAO.save(application);
        
        // 8. 【强一致性】同步更新统一待审核表状态
        try {
            pendingApprovalService.updateApprovalStatus(
                    com.pai4j.common.enums.PendingApprovalTypeEnum.GROUP_JOIN_REQUEST.getType(),
                    application.getId(),
                    request.getHandleResult(),
                    request.getApproverAccount(),
                    request.getApprovalRemark()
            );
            log.info("加群申请审批完成，统一待审核表已同步更新：applicationId={}, result={}", 
                    application.getId(), request.getHandleResult());
        } catch (Exception e) {
            log.error("同步更新统一待审核表失败，事务将回滚：applicationId={}", application.getId(), e);
            throw new RuntimeException("同步更新统一待审核表失败", e);
        }
        
        // 9. 如果同意，则调用joinGroup加入群聊
        // 注意：joinGroup会同时处理群成员表、账号关系表和缓存同步（强一致性）
        if (GroupInvitationStatusEnum.isAccepted(request.getHandleResult())) {
            JoinGroupRequestVO joinRequest = new JoinGroupRequestVO();
            joinRequest.setGroupPaiId(application.getGroupPaiId());
            joinRequest.setUserAccount(application.getApplicantAccount());
            joinRequest.setJoinType(GroupJoinTypeEnum.APPROVED.getType()); // 审批通过加入
            joinRequest.setInviterAccount(request.getApproverAccount());
            
            try {
                // 调用统一的加群方法，确保数据一致性
                JoinGroupResponseVO joinResult = groupMemberService.joinGroup(joinRequest);
                if (joinResult.getStatus() == 1) {
                    log.info("用户 {} 通过审批成功加入群聊 {}，审批人：{}，所有数据已同步（群成员表+账号关系表+缓存）", 
                            application.getApplicantAccount(), application.getGroupPaiId(), request.getApproverAccount());
                } else {
                    log.warn("用户 {} 通过审批加入群聊 {} 未成功，状态：{}，消息：{}", 
                            application.getApplicantAccount(), application.getGroupPaiId(), joinResult.getStatus(), joinResult.getMessage());
                    throw new BusinessException(joinResult.getMessage());
                }
            } catch (BusinessException e) {
                throw e;
            } catch (Exception e) {
                log.error("用户 {} 通过审批加入群聊 {} 失败", application.getApplicantAccount(), application.getGroupPaiId(), e);
                throw new BusinessException("加入群聊失败：" + e.getMessage());
            }
        }
        
        // 10. 记录操作日志
        String operationDesc = GroupInvitationStatusEnum.isAccepted(request.getHandleResult()) 
                ? "审批通过加群申请" : "拒绝加群申请";
        if (StringUtils.isNotBlank(request.getApprovalRemark())) {
            operationDesc += "，意见：" + request.getApprovalRemark();
        }
        
        recordOperationLog(request.getGroupPaiId(), request.getApproverAccount(), application.getApplicantAccount(),
                String.valueOf(GroupOperationTypeEnum.JOIN_GROUP.getType()), operationDesc);
        
        // 11. 清除相关缓存
        clearGroupPendingApplicationsCache(request.getGroupPaiId());
        clearUserApplicationStatusCache(request.getGroupPaiId(), application.getApplicantAccount());
        
        log.info("审批人 {} 处理了用户 {} 的加群申请，群：{}，结果：{}", 
                request.getApproverAccount(), application.getApplicantAccount(), 
                request.getGroupPaiId(), request.getHandleResult());
        
        return true;
    }

    /**
     * 获取群组的待审批申请列表（分页）
     * 仅群主和管理员可查看
     * 
     * @param groupPaiId 群组ID
     * @param requesterAccount 请求者账号（用于权限验证）
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @return 待审批申请分页列表
     */
    public Page<GroupJoinApplicationResponseVO> getGroupPendingApplications(
            String groupPaiId, String requesterAccount, int pageNum, int pageSize) {
        // 【关键】验证请求者是否是群主或管理员
        if (!groupMemberService.hasPermission(groupPaiId, requesterAccount, "admin")) {
            throw new BusinessException("您没有权限查看该群的待审批申请");
        }
        
        // 先从缓存查询
        String cacheKey = CACHE_PREFIX_GROUP_PENDING_APPLICATIONS + groupPaiId + ":" + pageNum + ":" + pageSize;
        String cachedResult = redisUtil.get(cacheKey);
        if (StringUtils.isNotBlank(cachedResult)) {
            log.debug("从缓存获取群 {} 的待审批申请列表", groupPaiId);
            // 注意：实际应用中需要正确处理Page对象的缓存和反序列化
        }
        
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
        Page<GroupJoinApplicationEntity> applications = groupJoinApplicationDAO
                .findByGroupPaiIdAndApplicationStatusOrderByCreateDateDesc(
                        groupPaiId, GroupInvitationStatusEnum.PENDING.getStatus(), pageable);
        
        // 转换为VO并填充用户信息
        Page<GroupJoinApplicationResponseVO> result = applications.map(this::convertToResponseVO);
        
        // 缓存结果（简化处理，实际应用中需要更复杂的缓存策略）
        redisUtil.set(cacheKey, String.valueOf(applications.getTotalElements()), CACHE_EXPIRE_SECONDS);
        
        return result;
    }

    /**
     * 获取群组的待审批申请数量
     * 仅群主和管理员可查看，用于显示红点提示
     * 
     * @param groupPaiId 群组ID
     * @param requesterAccount 请求者账号（用于权限验证）
     * @return 待审批申请数量
     */
    public Long getGroupPendingApplicationCount(String groupPaiId, String requesterAccount) {
        // 【关键】验证请求者是否是群主或管理员
        if (!groupMemberService.hasPermission(groupPaiId, requesterAccount, "admin")) {
            throw new BusinessException("您没有权限查看该群的待审批申请数量");
        }
        
        // 先从缓存查询
        String cacheKey = CACHE_PREFIX_GROUP_PENDING_APPLICATIONS + groupPaiId + ":count";
        String cachedCount = redisUtil.get(cacheKey);
        if (StringUtils.isNotBlank(cachedCount)) {
            return Long.valueOf(cachedCount);
        }
        
        Long count = groupJoinApplicationDAO.countByGroupPaiIdAndApplicationStatus(
                groupPaiId, GroupInvitationStatusEnum.PENDING.getStatus());
        
        // 缓存结果
        redisUtil.set(cacheKey, String.valueOf(count), CACHE_EXPIRE_SECONDS);
        
        return count;
    }

    /**
     * 从数据库恢复群组的待审批申请列表到Redis缓存
     * 用于群主/管理员离线后重新上线时恢复待审批列表
     *
     * @param groupPaiId 群组ID
     */
    public void restorePendingApplicationsFromDatabase(String groupPaiId) {
        try {
            // 从数据库查询所有待审批的加群申请
            List<GroupJoinApplicationEntity> pendingApplications = 
                    groupJoinApplicationDAO.findByGroupPaiIdAndApplicationStatus(
                            groupPaiId, GroupInvitationStatusEnum.PENDING.getStatus());
            
            if (pendingApplications == null || pendingApplications.isEmpty()) {
                log.debug("群 {} 没有待审批的加群申请", groupPaiId);
                return;
            }
            
            // 清除旧缓存
            clearGroupPendingApplicationsCache(groupPaiId);
            
            // 重建Redis缓存（简化处理，只缓存count）
            String cacheKey = CACHE_PREFIX_GROUP_PENDING_APPLICATIONS + groupPaiId + ":count";
            redisUtil.set(cacheKey, String.valueOf(pendingApplications.size()), CACHE_EXPIRE_SECONDS);
            
            log.info("群 {} 的待审批加群申请列表已从数据库恢复到Redis，共 {} 条", groupPaiId, pendingApplications.size());
        } catch (Exception e) {
            log.error("从数据库恢复群 {} 的待审批加群申请列表失败", groupPaiId, e);
        }
    }

    /**
     * 标记群组的待审批申请为已读
     * 同时更新数据库和清除Redis缓存
     *
     * @param groupPaiId 群组ID
     * @return 标记已读的记录数
     */
    public int markApplicationsAsRead(String groupPaiId) {
        log.info("标记群 {} 的待审批加群申请为已读", groupPaiId);
        
        try {
            // 更新数据库中的isRead字段
            int updatedCount = groupJoinApplicationDAO.markApplicationsAsRead(
                    groupPaiId, GroupInvitationStatusEnum.PENDING.getStatus());
            
            // 清除缓存，下次查询时从数据库重新加载
            clearGroupPendingApplicationsCache(groupPaiId);
            
            log.info("群 {} 的待审批加群申请已标记为已读，共 {} 条", groupPaiId, updatedCount);
            return updatedCount;
        } catch (Exception e) {
            log.error("标记群 {} 的待审批加群申请为已读失败", groupPaiId, e);
            throw new RuntimeException("标记待审批加群申请为已读失败", e);
        }
    }

    /**
     * 查询群组未读的待审批申请数量
     * 用于显示精确的未读红点数
     *
     * @param groupPaiId 群组ID
     * @return 未读待审批数量
     */
    public long countUnreadApplications(String groupPaiId) {
        try {
            long count = groupJoinApplicationDAO.countUnreadApplications(
                    groupPaiId, GroupInvitationStatusEnum.PENDING.getStatus());
            log.debug("群 {} 有 {} 条未读的待审批加群申请", groupPaiId, count);
            return count;
        } catch (Exception e) {
            log.error("查询群 {} 的未读待审批加群申请数量失败", groupPaiId, e);
            return 0;
        }
    }

    /**
     * 获取用户的申请历史（分页）
     */
    public Page<GroupJoinApplicationResponseVO> getUserApplicationHistory(String applicantAccount, int pageNum, int pageSize) {
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
        Page<GroupJoinApplicationEntity> applications = groupJoinApplicationDAO
                .findByApplicantAccountOrderByCreateDateDesc(applicantAccount, pageable);
        
        return applications.map(this::convertToResponseVO);
    }

    /**
     * 检查用户是否有待处理的申请
     */
    public boolean hasUserPendingApplication(String groupPaiId, String applicantAccount) {
        // 先从缓存查询
        String cacheKey = CACHE_PREFIX_USER_APPLICATION_STATUS + groupPaiId + ":" + applicantAccount;
        String cachedStatus = redisUtil.get(cacheKey);
        if (StringUtils.isNotBlank(cachedStatus)) {
            return Boolean.valueOf(cachedStatus);
        }
        
        Long count = groupJoinApplicationDAO.countByGroupPaiIdAndApplicantAccountAndApplicationStatus(
                groupPaiId, applicantAccount, GroupInvitationStatusEnum.PENDING.getStatus());
        
        boolean hasPending = count > 0;
        
        // 缓存结果
        redisUtil.set(cacheKey, String.valueOf(hasPending), CACHE_EXPIRE_SECONDS);
        
        return hasPending;
    }

    /**
     * 定时任务：更新过期的申请状态
     * 建议每小时执行一次
     */
    @Transactional
    public int updateExpiredApplications() {
        Date now = new Date();
        int count = groupJoinApplicationDAO.updateExpiredApplications(
                GroupInvitationStatusEnum.PENDING.getStatus(),
                GroupInvitationStatusEnum.EXPIRED.getStatus(),
                now,
                now
        );
        
        if (count > 0) {
            log.info("更新了 {} 条过期的加群申请", count);
        }
        
        return count;
    }

    /**
     * 转换为响应VO
     */
    private GroupJoinApplicationResponseVO convertToResponseVO(GroupJoinApplicationEntity entity) {
        GroupJoinApplicationResponseVO vo = new GroupJoinApplicationResponseVO();
        vo.setId(entity.getId());
        vo.setGroupPaiId(entity.getGroupPaiId());
        vo.setApplicantAccount(entity.getApplicantAccount());
        vo.setApplicationMessage(entity.getApplicationMessage());
        vo.setApplicationStatus(entity.getApplicationStatus());
        vo.setApplicationStatusName(GroupInvitationStatusEnum.getByStatus(entity.getApplicationStatus()).getStatusName());
        vo.setApproverAccount(entity.getApproverAccount());
        vo.setApprovalTime(entity.getApprovalTime());
        vo.setApprovalRemark(entity.getApprovalRemark());
        vo.setExpireTime(entity.getExpireTime());
        vo.setCreateDate(entity.getCreateDate());
        
        // 填充群组信息
        GroupInfoEntity groupInfo = groupInfoDAO.findByPaiId(entity.getGroupPaiId());
        if (groupInfo != null) {
            vo.setGroupName(groupInfo.getGroupName());
            vo.setGroupPhoto(groupInfo.getGroupPhoto());
        }
        
        // 填充申请人信息
        UserBaseResponseInfoVO applicant = userService.getUserInfoFromCache(entity.getApplicantAccount());
        if (applicant != null) {
            vo.setApplicantName(applicant.getUserName());
            vo.setApplicantPhoto(applicant.getPhoto());
        }
        
        // 填充审批人信息
        if (StringUtils.isNotBlank(entity.getApproverAccount())) {
            UserBaseResponseInfoVO approver = userService.getUserInfoFromCache(entity.getApproverAccount());
            if (approver != null) {
                vo.setApproverName(approver.getUserName());
            }
        }
        
        return vo;
    }

    /**
     * 记录操作日志
     */
    private void recordOperationLog(String groupPaiId, String operatorAccount, String targetAccount,
                                     String operationType, String operationDesc) {
        GroupOperationLogEntity log = new GroupOperationLogEntity();
        log.setGroupPaiId(groupPaiId);
        log.setOperatorAccount(operatorAccount);
        log.setTargetAccount(targetAccount);
        log.setOperationType(Integer.valueOf(operationType));
        log.setOperationDesc(operationDesc);
        log.setCreateDate(new Date());
        
        groupOperationLogDAO.save(log);
    }

    /**
     * 清除群待审批列表缓存
     */
    private void clearGroupPendingApplicationsCache(String groupPaiId) {
        Set<String> keys = redisUtil.keys(CACHE_PREFIX_GROUP_PENDING_APPLICATIONS + groupPaiId + ":*");
        if (keys != null && !keys.isEmpty()) {
            redisUtil.removeAll(keys);
            log.debug("清除群 {} 的待审批申请缓存，共 {} 个key", groupPaiId, keys.size());
        }
    }

    /**
     * 清除用户申请状态缓存
     */
    private void clearUserApplicationStatusCache(String groupPaiId, String applicantAccount) {
        String cacheKey = CACHE_PREFIX_USER_APPLICATION_STATUS + groupPaiId + ":" + applicantAccount;
        redisUtil.remove(cacheKey);
        log.debug("清除用户 {} 在群 {} 的申请状态缓存", applicantAccount, groupPaiId);
    }
    
    /**
     * 发送审批通知（互动消息）
     * 审批人处理申请后，如果有备注/理由，则通过消息队列发送互动消息通知申请人
     * 【架构优化】使用消息队列解耦，避免pai4j-user模块直接依赖pai4j-ugc模块
     * 
     * @param approverAccount 审批人账号
     * @param applicantAccount 申请人账号
     * @param groupPaiId 群组ID
     * @param approved true=通过，false=拒绝
     * @param remark 审批备注或拒绝理由
     */
    private void sendApprovalNotification(String approverAccount, String applicantAccount, 
                                          String groupPaiId, boolean approved, String remark) {
        try {
            // 获取群信息
            GroupInfoEntity groupInfo = groupInfoDAO.findByPaiId(groupPaiId);
            String groupName = groupInfo != null ? groupInfo.getGroupName() : "群聊";
            Long groupId = groupInfo != null ? groupInfo.getId() : null;
            
            // 获取审批人信息
            UserBaseResponseInfoVO approver = userService.getUserInfoFromCache(approverAccount);
            
            // 构建消息内容
            String action = approved ? "通过" : "拒绝";
            String messageContent = String.format("您的加群申请已被%s", action);
            
            // 创建消息通知VO
            MessageNotifyVO messageNotify = new MessageNotifyVO();
            messageNotify.setSenderId(approverAccount);
            messageNotify.setReceiverId(applicantAccount);
            messageNotify.setSender(approver);
            messageNotify.setMessage(messageContent);
            messageNotify.setContent(remark); // 审批备注作为详细内容
            messageNotify.setType(MessageTypeEnum.INTERACTION.getType());
            messageNotify.setTime(System.currentTimeMillis());
            
            // 设置资源信息（群信息）
            messageNotify.setResourceId(groupId);
            messageNotify.setResourceType("GROUP");
            messageNotify.setResourceTitle(groupName);
            
            // 通过消息队列发送互动通知
            // 由pai4j-ugc或pai4j-connect模块监听QUEUE_INTERACTION_NOTIFY频道并持久化到数据库
            messageQueueProducer.broadSend(MessageBroadChannelEnum.QUEUE_INTERACTION_NOTIFY, messageNotify);
            
            log.info("发送加群审批通知成功（通过MQ）：审批人={}, 申请人={}, 群={}, 结果={}, 备注={}",
                    approverAccount, applicantAccount, groupName, action, remark);
        } catch (Exception e) {
            log.error("发送加群审批通知失败：审批人={}, 申请人={}, 群={}",
                    approverAccount, applicantAccount, groupPaiId, e);
            // 互动消息发送失败不影响审批流程，只记录日志
        }
    }
}
